﻿' Copyright © Microsoft Corporation.  All Rights Reserved.
' This code released under the terms of the 
' Microsoft Public License (MS-PL, http://opensource.org/licenses/ms-pl.html.)
' <copyright file="SelectableItemsControl.vb" company="Microsoft">
'     Copyright © Microsoft Corporation. All rights reserved.
' </copyright>

Imports Microsoft.VisualBasic
Imports System
Imports System.Windows
Imports System.Windows.Controls
Imports System.Windows.Input
Imports System.Windows.Media

Namespace MediaPlayerExtensions
	Public Class SelectableItemsControl
		Inherits ItemsControl
		''' <summary>
		''' currently selected item
		''' </summary>
		Private m_SelectedItem As Object
		''' <summary>
		''' item hovering over
		''' </summary>
		Private m_HoverItem As Object
		''' <summary>
		''' index of item over
		''' </summary>
		Private m_HoverIndex As Integer
		''' <summary>
		''' dependancy property for currently selected item index
		''' </summary>
		Public Shared ReadOnly SelectedIndexProperty As DependencyProperty = DependencyProperty.Register("SelectedIndex", GetType(Integer), GetType(SelectableItemsControl), New PropertyMetadata(0, AddressOf OnSelectedIndexChanged))
		''' <summary>
		''' dependancy property for currently hovered over index
		''' </summary>
		Public Shared ReadOnly HoverIndexProperty As DependencyProperty = DependencyProperty.Register("HoverIndex", GetType(Integer), GetType(SelectableItemsControl), New PropertyMetadata(0, AddressOf OnHoverIndexChanged))
		''' <summary>
		''' selection changed event
		''' </summary>
		Public Event SelectionChanged As SelectionChangedEventHandler
		''' <summary>
		''' hovered over item changed event
		''' </summary>
		Public Event HoverChanged As SelectionChangedEventHandler
		''' <summary>
		''' create new SelectableItemsControl
		''' </summary>
		Public Sub New()
			SelectedIndex = -1
			m_HoverIndex = -1
		End Sub
		''' <summary>
		''' override ScrollIntoView to do nothing
		''' </summary>
		''' <param name="item"></param>
		Public Overridable Sub ScrollIntoView(ByVal item As Object)
		End Sub
		''' <summary>
		''' wire events for the content container of this items control
		''' </summary>
		Protected Overrides Sub PrepareContainerForItemOverride(ByVal element As DependencyObject, ByVal item As Object)
			Dim contentPresenter As ContentPresenter = TryCast(element, ContentPresenter)
			If contentPresenter IsNot Nothing Then
				AddHandler contentPresenter.MouseEnter, AddressOf OnItemMouseEnter
				AddHandler contentPresenter.MouseLeave, AddressOf OnItemMouseLeave
				AddHandler contentPresenter.MouseLeftButtonDown, AddressOf OnItemClicked
			End If

			MyBase.PrepareContainerForItemOverride(element, item)
		End Sub
		''' <summary>
		''' item clicked
		''' </summary>
		Private Sub OnItemClicked(ByVal sender As Object, ByVal e As MouseButtonEventArgs)
			Dim contentPresenter As ContentPresenter = TryCast(sender, ContentPresenter)
			' get the index
			Dim panel As Panel = TryCast(VisualTreeHelper.GetParent(contentPresenter), Panel)
			If panel Is Nothing Then
				Return
			End If

			' force the selected index changed call..
			SelectedIndex = -1
			SelectedIndex = panel.Children.IndexOf(contentPresenter)
		End Sub
		''' <summary>
		''' item hovered over, fire enter state in VSM
		''' </summary>
		Private Sub OnItemMouseEnter(ByVal sender As Object, ByVal e As MouseEventArgs)
			Dim contentPresenter As ContentPresenter = TryCast(sender, ContentPresenter)
			Dim child As Control = TryCast(VisualTreeHelper.GetChild(contentPresenter, 0), Control)
			If child Is Nothing Then
				Return
			End If
			VisualStateManager.GoToState(child, "MouseEnter", True)

			' determine what the hover item index is...
			Dim panel As Panel = TryCast(VisualTreeHelper.GetParent(contentPresenter), Panel)
			If panel Is Nothing Then
				Return
			End If

			HoverIndex = panel.Children.IndexOf(contentPresenter)
		End Sub
		''' <summary>
		''' item no longer hovered over, fire leave state in VSM
		''' </summary>
		Private Sub OnItemMouseLeave(ByVal sender As Object, ByVal e As MouseEventArgs)
			Dim contentPresenter As ContentPresenter = TryCast(sender, ContentPresenter)
			Dim child As Control = TryCast(VisualTreeHelper.GetChild(contentPresenter, 0), Control)
			If child Is Nothing Then
				Return
			End If
			VisualStateManager.GoToState(child, "MouseLeave", True)
		End Sub
		''' <summary>
		''' property wrapper for SelectedIndex dependancy property
		''' </summary>
		Public Property SelectedIndex() As Integer
			Get
				Return CInt(Fix(GetValue(SelectedIndexProperty)))
			End Get
			Set(ByVal value As Integer)
				SetValue(SelectedIndexProperty, value)
			End Set
		End Property
		''' <summary>
		''' SelectedIndex dependancy property changed
		''' </summary>
		Protected Shared Sub OnSelectedIndexChanged(ByVal obj As DependencyObject, ByVal args As DependencyPropertyChangedEventArgs)
			Dim list As SelectableItemsControl = TryCast(obj, SelectableItemsControl)
			If list IsNot Nothing Then
				list.UpdateSelectedIndex()
			End If
		End Sub
		''' <summary>
		''' property wrapper for HoverIndex dependancy property
		''' </summary>
		Public Property HoverIndex() As Integer
			Get
				Return CInt(Fix(GetValue(HoverIndexProperty)))
			End Get
			Set(ByVal value As Integer)
				SetValue(HoverIndexProperty, value)
			End Set
		End Property
		''' <summary>
		''' HoverIndex dependancy property changed
		''' </summary>
		''' <param name="obj"></param>
		''' <param name="args"></param>
		Protected Shared Sub OnHoverIndexChanged(ByVal obj As DependencyObject, ByVal args As DependencyPropertyChangedEventArgs)
			Dim list As SelectableItemsControl = TryCast(obj, SelectableItemsControl)
			If list IsNot Nothing Then
				list.UpdateHoverIndex()
			End If
		End Sub
		''' <summary>
		''' sync the HoverItem from the current hovered over index
		''' </summary>
		Private Sub UpdateHoverIndex()
			Dim hoverIndex As Integer = Math.Max(-1, Math.Min(Me.HoverIndex, Items.Count - 1))
			If hoverIndex = m_HoverIndex Then
				Return
			End If

			m_HoverIndex = hoverIndex
			If hoverIndex = -1 Then
				HoverItem = Nothing
			Else
				HoverItem = Items(m_HoverIndex)
			End If
		End Sub
		''' <summary>
		''' update SelectedItem from the currently selected item index
		''' </summary>
		Private Sub UpdateSelectedIndex()
			Dim selectedIndex As Integer = Math.Max(-1, Math.Min(Me.SelectedIndex, Items.Count - 1))

			If selectedIndex = -1 Then
				SelectedItem = Nothing
			Else
				SelectedItem = Items(Me.SelectedIndex)
			End If
		End Sub
		''' <summary>
		''' currently selected item
		''' </summary>
		Public Property SelectedItem() As Object
			Get
				Return m_SelectedItem
			End Get
			Set(ByVal value As Object)
				m_SelectedItem = value
				RaiseEvent SelectionChanged(Me, Nothing)
			End Set
		End Property
		''' <summary>
		''' current item hovered over
		''' </summary>
		Public Property HoverItem() As Object
			Get
				Return m_HoverItem
			End Get
			Set(ByVal value As Object)
				If value Is m_HoverItem Then
					Return
				End If

				m_HoverItem = value
				RaiseEvent HoverChanged(Me, Nothing)
			End Set
		End Property
	End Class
End Namespace
